<?php

namespace app\models;

use think\Db;
use think\Model;
use think\facade\Log;
use think\Facade\Env;


class Douyin extends Model
{
    protected $accesstoken;

    protected $config = [
        'app_id' => 'tt88e8fe5517d6858b01',
        'secret' => 'c0a512ced5d5e07febc2ca7719b92129e20b84f8',
        'url' => 'https://developer.toutiao.com/api/apps/',
    ];



    public function pay($paymentInfo)
    {
        $result = [
            'status' => false,
            'data' => [],
            'msg' => ''
        ];
        $url = $this->config['url'] . 'ecpay/v1/create_order';
        $data['app_id'] = $this->config['app_id']; //商户号
        $data['out_order_no'] = $paymentInfo['payment_id'];                    //商户订单号
        $data['total_amount'] = floor($paymentInfo['money'] * 10000) / 100;                        //总金额
        $data['subject'] = mb_substr($paymentInfo['pay_title'], 0, 42, 'utf-8');       //商品描述，不能超过128个字符，所以这里要截取，防止超过
        $data['body'] = mb_substr($paymentInfo['pay_title'], 0, 42, 'utf-8');       //商品描述，不能超过128个字符，所以这里要截取，防止超过
        $data['valid_time'] = 1;
        $data['notify_url'] = url('other/callback?type=2', [], '', true);
        $data['sign'] = $this->makeSign($data);
        $data = json_encode($data, true);
        $res = $this->api_curl($url, $data, 1);
        if (isset($res) && $res['err_no'] == 0 && !empty($res['data'])) {
            $result = [
                'status' => true,
                'data' => $res['data'],
                'msg' => '获取成功'
            ];
        }
        return $result;
    }


    //核销
    public function push($payment)
    {
        $url = $this->config['url'] . 'order/v2/push';
        $token = $this->accessToken();
        if ($token) {
            $data['access_token'] = $this->accesstoken;
            $data['app_name'] = 'douyin';
            $data['open_id'] = $payment['openid'];
            $data['order_detail'] = json_encode($payment['detail'],true);
            $data['order_status'] = 4;
            $data['order_type'] = 0;
            $data['update_time'] = time() * 1000;
            $data = json_encode($data, true);
            $res = $this->api_curl($url, $data, 1);
            return $res;
        }
        return false;
    }

    public function settle($payment)
    {
        $url = $this->config['url'] . 'ecpay/v1/settle';
        $data['app_id'] = $this->config['app_id']; //商户号
        $data['out_settle_no'] = $payment['paymentid'];
        $data['out_order_no'] = $payment['paymentid'];
        $data['settle_desc'] = $payment['text'];
        $data['sign'] = $this->makeSign($data);
        $data = json_encode($data, true);
        $res = $this->api_curl($url, $data, 1);
        return $res;
    }

    public function query_settle($payment)
    {
        $url = $this->config['url'] . 'ecpay/v1/query_settle';
        $data['app_id'] = $this->config['app_id']; //商户号
        $data['out_settle_no'] = $payment['paymentid'];
        $data['sign'] = $this->makeSign($data);
        $data = json_encode($data, true);
        $res = $this->api_curl($url, $data, 1);
        return $res;
    }



    public function refund($refundInfo, $paymentInfo)
    {
        $refund_amount = floor($refundInfo['money'] * 10000) / 100;
        $url = $this->config['url'] . 'ecpay/v1/create_refund';
        $data['app_id'] = $this->config['app_id'];
        $data['out_order_no'] = $paymentInfo['payment_id']; //平台支付单号
        $data['out_refund_no'] = $refundInfo['refund_id']; //退款单号
        $data['reason'] = '退款';
        $data['refund_amount'] = (int)$refund_amount; //退款金额
        $data['notify_url'] = 'https://' . Env::get('app.api_url') . '/other/callback3?type=2';
        $data['sign'] = $this->makeSign($data);
        $data = json_encode($data, true);
        $res = $this->api_curl($url, $data, 1);
        return $res;
    }


    public function callback()
    {
        $result = [
            'status' => false,
            'data' => [],
            'msg' => ''
        ];
        //获取通知的数据
        $xml = file_get_contents('php://input');
        $data = json_decode($xml, true);
        if (!$data || empty($data['msg'])) {
            return $result;
        }
        $sign = $this->getNotifySign($data, 1111);
        if ($data['msg_signature'] == $sign) {
            Log::write($data, 'douyin');
            $dresult = json_decode($data['msg'], true); // 进行签名验证
            //说明值没问题，并且验证签名通过
            $payment =  (new Payment())->where(['paymentid' => $dresult['cp_orderno'], 'paytype' => 2])->find();
            if (empty($payment)) {
                $result['msg'] = 'fail';
                return $result;
            }
            if ($payment['status'] == 2) {
                $result['status'] = true;
                $result['msg'] = 'success';
                return $result;
            }
            switch ($payment['type']) {
                case '1':
                    $order = (new Order())->where('ordersn', $payment['ordersn'])->where('status', 1)->find();
                    if (empty($order)) {
                        $result['msg'] = 'fail';
                        return $result;
                    }
                    break;
                case '2':
                    $parmes = json_decode($payment['parmes'], true) ?? [];
                    break;
                case '3':
                    $iorder = (new IntergralOrder())->where('id', $payment['ordersn'])->where('status', 0)->find();
                    if (empty($iorder)) {
                        $result['msg'] = 'fail';
                        return $result;
                    }
                    break;
                case '4':
                    $user = (new User())->where('id', $payment['ordersn'])->find();
                    break;
                case '5':
                    $coupons = [];
                    $promo = (new Promo())->where('id', $payment['ordersn'])->find();
                    $promo['coupon'] = json_decode($promo['coupon'], true) ?? [];
                    $parmes = json_decode($payment['parmes'], true) ?? [];
                    $code = rekey(new Pkey(), '');
                    if (empty($code)) {
                        break;
                    }
                    break;
                default:
                    $result['msg'] = 'fail';
                    return $result;
                    break;
            }
            Db::startTrans();
            try {
                (new Payment())->where(['id' => $payment['id'], 'status' => 1])
                    ->update([
                        'status' => 2,
                        'out_refund_no' => $dresult['payment_order_no'] ?? 0,
                        'paydata' => serialize($dresult)
                    ]);
                if ($payment['type'] == 1) {
                    (new Order())->where('id', $order['id'])->where('status', 1)->update(['status' => 2, 'payment' => 3, 'paytime' => date('Y-m-d H:i:s')]);
                }
                if ($payment['type'] == 3) {
                    (new IntergralOrder())->where('id', $payment['ordersn'])->where('status', 0)->update(['status' => 1, 'payment' => 2]);
                }
                if ($payment['type'] == 4 && $payment['money'] > 0) {
                    (new User())->MondyEdit($user['id'], $user['money'], $payment['money'], 1, 0, '充值到账');
                }
                if ($payment['type'] == 2 && !empty($parmes)) {
                    $user = (new User())->where('id', $parmes['user_id'])->find();
                    if ($user['level'] < $parmes['level']) {
                        $endtime = time() + 86400 * $parmes['days'];
                    } else {
                        $endtime = strtotime($user['level_time']) + 86400 * $parmes['days'];
                    }
                    (new User())->where('id', $parmes['user_id'])->update(['level' => $parmes['level'], 'level_time' => date('Y-m-d', $endtime)]);
                    $mycoupon = [];
                    $mycoupon1 = []; //抵扣券
                    foreach ($parmes['coupon'] as $coupon) {
                        $mycoupon[] = [
                            'user_id' => $parmes['user_id'],
                            'getmoney' => $coupon['getmoney'],
                            'money' => $coupon['money'],
                            'status' => 1,
                            'remark' => '购买会员赠送',
                            'text' => '本券由平台发放，最终解释权归平台所有',
                            'endtime' => date('Y-m-d H:i:s', time() + 86400 * $coupon['days'])
                        ];
                    }
                    foreach ($parmes['coupons'] as $coupon) {
                        $coupon['type'] = implode(',', $coupon['type']);
                        $mycoupon1[] = [
                            'type' => 1,
                            'types' => 2,
                            'user_id' => $parmes['user_id'],
                            'productid' => $coupon['type'],
                            'system' => 6,
                            'number' => 1,
                            'status' => 1,
                            'endtime' => date('Y-m-d H:i:s', time() + 86400 * $coupon['days']),
                            'btmoney' => $coupon['money']
                        ];
                    }
                    if (count($mycoupon) > 0) {
                        (new Coupon())->saveAll($mycoupon);
                    }
                    if (count($mycoupon1) > 0) {
                        (new Coupon())->saveAll($mycoupon1);
                    }
                }
                if ($payment['type'] == 5) {
                    //插入秘钥记录
                    $keyid = (new Pkey())->insertGetId(['promoid' => $promo['id'], 'code' => $code, 'type' => 2, 'status' => 2, 'user_id' => $parmes['user_id']]);
                    foreach ($promo['coupon'] as $coupon) {
                        $coupon['type'] = implode(',', $coupon['type']);
                        $coupons[] = [
                            'type' => 1,
                            'types' => 2,
                            'user_id' => $parmes['user_id'],
                            'agentid' => $promo['agentid'],
                            'productid' => $coupon['type'],
                            'number' => 1,
                            'system' => 5,
                            'status' => 1,
                            'endtime' => date('Y-m-d H:i:s', time() + 86400 * $coupon['days']),
                            'promo' => $promo['id'],
                            'keyid' => $keyid,
                            'btmoney' => $coupon['money']
                        ];
                    }
                    if (count($coupons) > 0) {
                        (new Coupon())->allowfield(true)->saveAll($coupons);
                    }
                }
                Db::commit();
            } catch (\Exception $e) {
                Log::write($e->getMessage(), 'douyin');
                Db::rollback();
                $result['msg'] = 'fail';
                return $result;
            }
            $result['status'] = true;
            $result['msg'] = 'success';
        } else {
            $result['msg'] = 'fail';
            return $result;
        }
        return $result;
    }

    public function callback2()
    {
        $result = [
            'status' => false,
            'data' => [],
            'msg' => ''
        ];
        //获取通知的数据
        $xml = file_get_contents('php://input');
        $data = json_decode($xml, true);
        if (!$data || empty($data['msg'])) {
            return $result;
        }
        $sign = $this->getNotifySign($data, 1111);
        if ($data['msg_signature'] == $sign) {
            //说明值没问题，并且验证签名通过
            $dresult = json_decode($data['msg'], true); // 进行签名验证
            $payment = (new Payment())->where(['paymentid' => $dresult['cp_refundno']])->find();
            if (!empty($payment)) {
                //订单进行取消操作
                Db::startTrans();
                try {
                    (new Payment())->where(['id' => $payment['id']])->update(['refund' => 2]);
                    Db::commit();
                } catch (\Exception $e) {
                    Db::rollback();
                    Log::write($e->getMessage(), 'refund');
                    return $result;
                }
                $result['status'] = true;
                $result['msg'] = 'success';
            }
        } else {
            $result['msg'] = 'fail';
            return $result;
        }
        return $result;
    }

    public function makeSign($map)
    {
        $rList = array();
        foreach ($map as $k => $v) {
            if ($k == "other_settle_params" || $k == "app_id" || $k == "sign" || $k == "thirdparty_id")
                continue;
            $value = trim(strval($v));
            $len = strlen($value);
            if ($len > 1 && substr($value, 0, 1) == "\"" && substr($value, $len, $len - 1) == "\"")
                $value = substr($value, 1, $len - 1);
            $value = trim($value);
            if ($value == "" || $value == "null")
                continue;
            array_push($rList, $value);
        }
        array_push($rList, "UyePLoJLdjHoFjP3pIlhZfanuQYW38phqrEfFE5Y");
        sort($rList, 2);
        return md5(implode('&', $rList));
    }


    // **************** 以下方法 是字节小程序支付 签名处理方式

    public function getNotifySign(array $body, string $secret)
    {

        $filtered = [];
        foreach ($body as $key => $value) {
            if (in_array($key, ['msg_signature', 'type'])) {
                continue;
            }
            $filtered[] =
                is_string($value)
                ? trim($value)
                : $value;
        }
        $filtered[] = trim($secret);
        sort($filtered, SORT_STRING);
        $filtered = trim(implode('', $filtered));
        return sha1($filtered);
    }

    /**
     * Get session info by code.
     *
     * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
     *
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     */
    public function qrcode($path = '', $width = 400, $set_icon = true, $line_color =  ['r' => 0, 'g' => 0, 'b' => 0], $background = ['r' => 255, 'g' => 255, 'b' => 255])
    {
        $token = $this->accessToken();
        if ($token) {
            $params = [
                'access_token' => $this->accesstoken,
                'appname' => 'douyin',
                'path' => urlencode($path),
                'width' => $width,
                "line_color" => $line_color,
                "background" => $background,
                'set_icon' => $set_icon
            ];
            $params = json_encode($params, true);
            $result = $this->api_curl($this->config['url'] . 'qrcode', $params, 2);
            if (isset($result)) {
                return $result;
            }
        }
        return false;
    }

    /**
     * Get session info by code.
     *
     * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string
     *
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     */
    public function session(string $code)
    {
        $token = $this->accessToken();
        if ($token) {
            $params = [
                'appid' => $this->config['app_id'],
                'secret' => $this->config['secret'],
                'code' => $code,
                'access_token' => $this->accesstoken
            ];
            $params = json_encode($params, true);
            $result = $this->api_curl($this->config['url'] . 'v2/jscode2session', $params, 1);
            if (isset($result) && $result['err_no'] == 0) {
                return $result['data'];
            }
        }
        return false;
    }


    public function accessToken()
    {
        $params = [
            'appid' => $this->config['app_id'],
            'secret' => $this->config['secret'],
            'grant_type' => 'client_credential'
        ];
        $params = json_encode($params, true);
        $result = $this->api_curl($this->config['url'] . 'v2/token', $params, 1);
        if (isset($result) && $result['err_no'] == 0) {
            $this->accesstoken = $result['data']['access_token'];
            return true;
        }
        return false;
    }

    function api_curl($url, $data = false, $ispost = 0)
    {
        $headers = array();
        array_push($headers, "Content-Type" . ":" .  "application/json");
        $httpInfo = array();
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 300);
        curl_setopt($ch, CURLOPT_TIMEOUT, 300);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_FAILONERROR, false);
        if (1 == strpos("$" . $url, "https://")) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        }
        if ($ispost) {
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
            curl_setopt($ch, CURLOPT_URL, $url);
        } else {
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
            $data = http_build_query($data);
            if ($data) {
                curl_setopt($ch, CURLOPT_URL, $url . '?' . $data);
            } else {
                curl_setopt($ch, CURLOPT_URL, $url);
            }
        }
        $response = curl_exec($ch);
        if ($response === FALSE) {
            return false;
        }

        if ($ispost == 2) {
            curl_close($ch);
            return $response;
        }
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $httpInfo = array_merge($httpInfo, curl_getinfo($ch));
        curl_close($ch);
        $response = json_decode($response, true);

        return $response;
    }
}
